/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.space.house.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.util.DictItemOption;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.resolver.DictItemResolver;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.excel.vo.ErrorMessage;
import com.fuyao.cloud.space.constant.EdificeConstant;
import com.fuyao.cloud.space.constant.HouseConstant;
import com.fuyao.cloud.space.constant.RegionalConstant;
import com.fuyao.cloud.space.constant.StoreyConstant;
import com.fuyao.cloud.space.edifice.service.RoomEdificeService;
import com.fuyao.cloud.space.entity.*;
import com.fuyao.cloud.space.house.mapper.RoomHouseMapper;
import com.fuyao.cloud.space.house.service.RoomHouseService;
import com.fuyao.cloud.space.position.mapper.RoomPositionMapper;
import com.fuyao.cloud.space.regional.mapper.RoomRegionalMapper;
import com.fuyao.cloud.space.regional.service.RoomRegionalService;
import com.fuyao.cloud.space.roomland.mapper.RoomLandMapper;
import com.fuyao.cloud.space.storey.service.RoomStoreyService;
import com.fuyao.cloud.space.vo.ExcelExportHouseVO;
import com.fuyao.cloud.space.vo.ExcelImportHouseVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 房屋信息表
 *
 * @author liyue
 * @date 2021-11-12 14:46:49
 */
@Service
@AllArgsConstructor
public class RoomHouseServiceImpl extends ServiceImpl<RoomHouseMapper, RoomHouse> implements RoomHouseService {

	private final RoomEdificeService fyRoomEdificeService;
	private final RoomStoreyService fyRoomStoreyService;
	private final RoomPositionMapper roomPositionMapper;
	private final RoomRegionalService roomRegionalService;

	@Override
	public boolean save(RoomHouse entity) {
		setFieldValue(entity);
		return super.save(entity);
	}

	@Override
	public boolean updateById(RoomHouse entity) {
		setFieldValue(entity);
		return super.updateById(entity);
	}

	@Override
	public R getOptionList(String type) {
		Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(HouseConstant.HOUSE_OPTION_TYPES);
		return R.ok(resultMap.get(type));
	}

	@Override
	public List<ExcelExportHouseVO> listHouse(QueryWrapper<RoomHouse> query) {
		// 查询字典信息
		Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(HouseConstant.HOUSE_OPTION_TYPES);

		List<RoomHouse> fyRoomEdifices = this.baseMapper.selectListByScope(query, new DataScope());
		return fyRoomEdifices.stream().map(entity -> {
			ExcelExportHouseVO exportVO = new ExcelExportHouseVO();
			BeanUtils.copyProperties(entity, exportVO);

			exportVO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(HouseConstant.HOUSE_STATUS), entity.getStatusStr()));
			exportVO.setOrientation(DictItemResolver.getDictOptionLabel(resultMap.get(HouseConstant.HOUSE_FACE), entity.getOrientation()));
			exportVO.setLayout(DictItemResolver.getDictOptionLabel(resultMap.get(HouseConstant.HOUSE_UNIT_YPE), entity.getLayout()));
			exportVO.setRenovation(DictItemResolver.getDictOptionLabel(resultMap.get(HouseConstant.HOUSE_PROGRAM), entity.getRenovation()));
			exportVO.setTypeName(DictItemResolver.getDictOptionLabel(resultMap.get(HouseConstant.HOUSE_TYPE), entity.getTypeCode()));
			//字典转换
			return exportVO;
		}).collect(Collectors.toList());
	}

	@Override
	public List<Tree<String>> selectTree() {
		// 权限内房屋信息
		LambdaQueryWrapper<RoomHouse> queryWrapper = Wrappers.<RoomHouse>query().lambda().ne(RoomHouse::getTypeCode, "CK");
		List<TreeNode<String>> collect = getTreeNode(queryWrapper);
		return TreeUtil.build(collect, RegionalConstant.REGIONAL_TREE_NAME+".0");
	}

	@Override
	public List<Tree<String>> warehouseTree() {
		LambdaQueryWrapper<RoomHouse> queryWrapper = Wrappers.<RoomHouse>query().lambda().eq(RoomHouse::getTypeCode, "CK");
		// 权限内房屋信息
		List<TreeNode<String>> collect = getTreeNode(queryWrapper);
		return TreeUtil.build(collect, RegionalConstant.REGIONAL_TREE_NAME+".0");
	}

	@Override
	public List<TreeNode<String>> getTreeNode(LambdaQueryWrapper<RoomHouse> queryWrapper) {
		// 权限内房屋信息
		List<TreeNode<String>> collect = fyRoomStoreyService.getTreeNode();

		List<RoomHouse> houseList = this.baseMapper.selectList(queryWrapper);
		// 查询数据权限内房屋信息
		List<Long> houseOwnIdList = this.baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
				.map(RoomHouse::getDeptId).collect(Collectors.toList());

		collect.addAll(houseList.stream()
				.sorted(Comparator.comparing(RoomHouse::getCreateTime)).map(house -> {
					TreeNode<String> treeNode = new TreeNode();
					treeNode.setId(HouseConstant.HOUSE_TREE_NAME+"."+house.getId());
					treeNode.setParentId(StoreyConstant.STOREY_TREE_NAME+"."+house.getStoreyId());
					treeNode.setName(house.getName());
					treeNode.setWeight(house.getOrdernumber());
					// 有权限不返回标识
					Map<String, Object> extra = new HashMap<>(8);
					extra.put("isLock", !houseOwnIdList.contains(house.getDeptId()));
					extra.put("createTime", house.getCreateTime());
					extra.put("affiliName",HouseConstant.HOUSE_TREE_NAME);
					extra.put("affiliParentName",EdificeConstant.EDIFICE_TREE_NAME);
					extra.put("idCard", house.getId());
					treeNode.setExtra(extra);
					return treeNode;
				}).collect(Collectors.toList()));

		return collect;
	}

	/**
	 * 树查询
	 * @param page        前端分页
	 * @param id          可以是自己的id，也肯能时父类的id
	 * @param affiliName  所属模块名称
	 * @return
	 */
	@Override
	public Page<RoomHouse> getTreePage(Page page, Long id, String affiliName) {
		List<Long> ids=getTreeParam(id,affiliName);
		ids.add(0L); // 如果为空会报错
		return this.baseMapper.selectPage(page,Wrappers.<RoomHouse>lambdaQuery().in(RoomHouse::getId,ids));
	}

	@Override
	public List<Long> getTreeParam(Long id, String affiliName) {
		List<Long> ids;
		if (affiliName.equals(StoreyConstant.STOREY_TREE_NAME)){
			ids=this.baseMapper.getIdByStoreyId(id);
		} else if (affiliName.equals(EdificeConstant.EDIFICE_TREE_NAME)){
			ids=this.baseMapper.getIdByEdificeId(id);
		} else{
			List<Long> parentIds= this.fyRoomStoreyService.getTreeParam(id,affiliName);
			if (parentIds.size()==0){
				return new ArrayList<>();
			}
			ids=this.baseMapper.getIdByParentId(parentIds.toArray(new Long[parentIds.size()]));
		}
		return Optional.ofNullable(ids).orElse(new ArrayList<>());
	}

	@Override
	public R importHouse(List<ExcelImportHouseVO> excelVOList, BindingResult bindingResult) {
		// 通用校验获取失败的数据
		List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
		// 个性化校验逻辑
		List<RoomEdifice> regionalList = this.fyRoomEdificeService.list(Wrappers.emptyWrapper());
		List<RoomStorey> storeyList = this.fyRoomStoreyService.list(Wrappers.emptyWrapper());
		Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(HouseConstant.HOUSE_OPTION_TYPES);

		if (CollUtil.isEmpty(excelVOList)) {
			assert errorMessageList != null;
			errorMessageList.add(new ErrorMessage("无数据导入"));
			return R.failed(errorMessageList);
		}
		// 执行数据插入操作 组装 FyRoomHouse
		for (int i = 0; i < excelVOList.size(); i++) {
			ExcelImportHouseVO excel = excelVOList.get(i);
			Set<String> errorMsg = new HashSet<>();
			// 拷贝属性
			RoomHouse house = new RoomHouse();
			BeanUtils.copyProperties(excel, house);
			// 楼栋信息
			Optional<RoomEdifice> edificeOptional = regionalList.stream().filter(t -> t.getCode().equals(excel.getEdficeCode())).findFirst();
			if (edificeOptional.isPresent()) {
				RoomEdifice edifice = edificeOptional.get();
				house.setEdificeId(edifice.getId());
			} else {
				errorMsg.add(String.format(" 所属楼栋编码不存在: %s ", excel.getEdficeCode()));
			}
			// 楼层信息
			Optional<RoomStorey> storeyOptional = storeyList.stream().filter(t -> t.getCode().equals(excel.getStoreyCode())).findFirst();
			if (storeyOptional.isPresent()) {
				RoomStorey fyRoomStorey = storeyOptional.get();
				house.setStoreyId(fyRoomStorey.getId());
				house.setStoreyName(fyRoomStorey.getName());
			} else {
				errorMsg.add(String.format(" 所属楼层编码不存在: %s ", excel.getStoreyCode()));
			}
			// 名称转字典编码
			String status = DictItemResolver.getDictOptionValue(resultMap.get(HouseConstant.HOUSE_STATUS), excel.getStatus());
			if (StrUtil.isNotEmpty(status) && NumberUtil.isInteger(status)) {
				house.setStatus(status);
			}
			house.setOrientation(DictItemResolver.getDictOptionValue(resultMap.get(HouseConstant.HOUSE_FACE), excel.getOrientation()));
			house.setLayout(DictItemResolver.getDictOptionValue(resultMap.get(HouseConstant.HOUSE_UNIT_YPE), excel.getLayout()));
			house.setRenovation(DictItemResolver.getDictOptionValue(resultMap.get(HouseConstant.HOUSE_PROGRAM), excel.getRenovation()));
			house.setTypeCode(DictItemResolver.getDictOptionValue(resultMap.get(HouseConstant.HOUSE_TYPE), excel.getTypeName()));
			house.setTypeName(house.getTypeName());

			// 数据合法情况
			if (CollUtil.isEmpty(errorMsg)) {
				insertExcelHouse(house);
			} else {
				// 数据不合法情况
				errorMessageList.add(new ErrorMessage((long) (i + 2), errorMsg));
			}
		}
		if (CollUtil.isNotEmpty(errorMessageList)) {
			return R.failed(errorMessageList);
		}
		return R.ok();
	}

	@Override
	public boolean removeById(Serializable id) {
		Long count = roomPositionMapper.selectCount(Wrappers.<RoomPosition>lambdaQuery().eq(RoomPosition::getHouseId, id));
		Assert.isTrue((count <= 0), "该房屋信息关联位置信息，请选删除关联位置信息数据后，再删除房屋数据");
		return super.removeById(id);
	}

	@Override
	public List<Tree<String>> lazyTree(String storeyId) {
		String[] ids=storeyId.split("-");
		if (ids.length == 2){
			if (!ids[0].equals(StoreyConstant.STOREY_TREE_NAME)){
				return new ArrayList<>();
			}
		}
		return lazyTree(Long.valueOf(ids[1]));
	}

	@Override
	public List<Tree<String>> lazyTree(Long storeyId) {
		// lambda 查询条件
		LambdaQueryWrapper<RoomHouse> wrappers=Wrappers.<RoomHouse>lambdaQuery().eq(RoomHouse::getStoreyId,storeyId);
		List<RoomHouse> houseList = this.baseMapper.selectList(wrappers);
		// 查询数据权限内房屋信息
		List<Long> houseOwnIdList = this.baseMapper.selectListByScope(wrappers, new DataScope()).stream()
				.map(RoomHouse::getDeptId).collect(Collectors.toList());
		// 权限内房屋信息
		List<TreeNode<String>> collect = houseList.stream()
				.sorted(Comparator.comparing(RoomHouse::getCreateTime)).map(house -> {
					TreeNode<String> treeNode = new TreeNode();
					treeNode.setId(HouseConstant.HOUSE_TREE_NAME+"."+house.getId());
					treeNode.setParentId(StoreyConstant.STOREY_TREE_NAME+"."+house.getStoreyId());
					treeNode.setName(house.getName());
					treeNode.setWeight(house.getOrdernumber());
					// 有权限不返回标识
					Map<String, Object> extra = new HashMap<>(8);
					extra.put("isLock", !houseOwnIdList.contains(house.getDeptId()));
					extra.put("createTime", house.getCreateTime());
					extra.put("affiliName",HouseConstant.HOUSE_TREE_NAME);
					extra.put("affiliParentName",EdificeConstant.EDIFICE_TREE_NAME);
					extra.put("idCard", house.getId());
					treeNode.setExtra(extra);
					return treeNode;
				}).collect(Collectors.toList());
		return TreeUtil.build(collect, StoreyConstant.STOREY_TREE_NAME + "."+storeyId);
	}

	@Override
	public R batchDelete(List<Long> ids) {
		Long count = roomPositionMapper.selectCount(Wrappers.<RoomPosition>lambdaQuery().in(RoomPosition::getHouseId, ids));
		Assert.isTrue((count <= 0), "该房屋信息关联位置信息，请选删除关联位置信息数据后，再删除房屋数据");

		boolean remove = this.removeByIds(ids);
		if (remove) {
			return R.ok(CommonConstants.SUCCESS, String.format("成功删除%s条数据", ids.size()));
		}
		return R.failed(ids, "删除失败");
	}

	/**
	 * 保存导入的信息
	 *
	 * @param house 房屋对象
	 */
	private void insertExcelHouse(RoomHouse house) {
		setFieldValue(house);
		super.save(house);
	}

	/**
	 * 保存修改时填充值
	 *
	 * @param house 房屋对象
	 */
	private void setFieldValue(RoomHouse house) {
		if (StrUtil.isEmpty(house.getCode())) {
			String numberStr = NumberResolver.getNumberStr(HouseConstant.HOUSE_NUMBER_TYPE, HouseConstant.HOUSE_CODE).getData();
			house.setCode(numberStr);
		}
		if (house.getOrdernumber()==null || house.getOrdernumber()==0){
			house.setOrdernumber(NumberResolver.getNumberValue(HouseConstant.HOUSE_NUMBER_TYPE, HouseConstant.HOUSE_CODE).getData().intValue());
		}
		if(StrUtil.isNotEmpty(house.getTypeCode())){
			String typeName = DictItemResolver.getDictOptionLabel(Collections.singletonList(HouseConstant.HOUSE_TYPE),house.getTypeCode());
			house.setTypeName(typeName);
		}
		RoomEdifice edifice = this.fyRoomEdificeService.getById(house.getEdificeId());
		RoomStorey storey = this.fyRoomStoreyService.getById(house.getStoreyId());
		RoomRegional regional = this.roomRegionalService.getById(edifice.getRegionalId());
		house.setStoreyName(storey.getName());
		// 土地名称+区域名称+楼栋名称+房屋名称
		StringBuilder parentFullName = new StringBuilder();
		parentFullName.append(StrUtil.isEmpty(regional.getLandName()) ? StrUtil.EMPTY : regional.getLandName() + ".");
		parentFullName.append(edifice.getRegionalMc()).append(".");
		parentFullName.append(edifice.getName()).append(".");
		parentFullName.append(storey.getName());
		house.setParentFullname(parentFullName.toString());
		// 数据全编码
		house.setDataCode(storey.getDataCode() + "." + house.getCode());
	}
}
